﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Globalization;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

namespace NextPhase.Tests.StepHelpers
{
	// TODO: This should probably be in the jTest framework

	/// <summary>
	/// http://skysanders.net/subtext/archive/2010/04/11/a-general-purpose-visual-studio-2008-development-server-webdev.webserver.exe-test.aspx
	/// </summary>
	internal class WebServer
	{
		private const string WebDevPathx64 =
			@"C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\10.0\WebDev.WebServer40.EXE";

		private const string WebDevPathx86 =
			@"C:\Program Files\Common Files\Microsoft Shared\DevServer\10.0\WebDev.WebServer40.EXE";

		private const int _port = 9999;
		private const string _vdir = "/";
		// private const string WebsiteLocation = "..\\..\\..\\..\\..\\Source\\NextPhase\\NextPhase";
		private const string WebServerProcessKey = "WebServer";

		private static Process _webServerProcess;
		private static Process WebServerProcess {
			get
			{
				if (_webServerProcess == null)
				{
					throw new InvalidOperationException("You have not setup the webserver yet.");
				}
				return _webServerProcess;
			}
			set
			{
				_webServerProcess = value;
			}
		}

		/// <summary>
		/// Ensure that an instance of WebDev.WebServer.exe is running and serving the target site. 
		/// </summary>
		/// <param name="sitePath">path of the website to serve, can be absolute or relative</param>
		/// <param name="webSiteDirectory">The file path to the directory to start.</param>
		/// <returns>A process instance to hold on and then close.</returns>
		internal static void StartServer(String webSiteDirectory)
		{
			if (IsPortAvailable(_port))
			{
				string sitePath = Path.GetFullPath(webSiteDirectory);

				// try x86 first
				string webDevPath = WebDevPathx86;
				if (!File.Exists(webDevPath))
				{
					// then x64
					webDevPath = WebDevPathx64;
					if (!File.Exists(webDevPath))
					{
						throw new FileNotFoundException("Cannot find WebDev.WebServer.exe");
					}
				}

				string devServerCmdLine = String.Format(CultureInfo.InvariantCulture,
														"/port:{0} /path:\"{1}\" /vpath:\"{2}\"", _port, sitePath,
														_vdir);
				try
				{
					Process webServer = Process.Start(webDevPath, devServerCmdLine);
					WebServerProcess = webServer;
				}
				catch (Exception ex)
				{
					throw new InvalidProgramException("Could not start webserver", ex);
				}
			}
		}

		private static bool IsPortAvailable(int port)
		{
			IPEndPoint ep = new IPEndPoint(IPAddress.Any, port);
			Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);

			try
			{
				socket.Bind(ep);
				socket.Close();
				//Port available
			}
			catch (SocketException)
			{
				return false;
			}

			return true;
		}

		private static Uri GetFullPath(String relitiveUrl)
		{
			// Check for valid arguments
			if (relitiveUrl == null)
				throw new ArgumentNullException("relitiveUrl");
			if (relitiveUrl.StartsWith("/")
				|| relitiveUrl.StartsWith("htt", StringComparison.CurrentCultureIgnoreCase))
				throw new ArgumentException("Use a relitive Url");

			return new Uri("http://localhost:" + _port  + "/" + relitiveUrl);
		}
	}
}
